#include "log.h"

#include <assert.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <time.h>

#if WIN32
#include <Windows.h>
#define HANGUP() DebugBreak()
#else
#include <unistd.h>
#define HANGUP() __builtin_trap()
#endif

void log_write(LOG_LEVEL level, const char *format, ...) {
    static const char *level_texts[] = {
        "[T]",
        "[D]",
        "[I]",
        "[W]",
        "[E]",
        "[F]"
    };

    char format_buffer[1024];
    memset(format_buffer, 0x00, sizeof(format_buffer));
    char message_buffer[8192];
    memset(message_buffer, 0x00, sizeof(message_buffer));
    time_t now = time(0);
    struct tm tm;
#if defined(WIN32)
    const errno_t ret = localtime_s(&tm, &now);
    assert(ret == 0);
#elif defined(__unix__)
    tm = *localtime_r(&now, &tm);
#endif

    snprintf(format_buffer, sizeof(format_buffer),
             "[%04d/%02d/%02d %02d:%02d:%02d]%s:%s\n",
             tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, level_texts[level], format);

    va_list args;
    va_start(args, format);
    int length = vsnprintf(message_buffer, sizeof(message_buffer), format_buffer, args);
    va_end(args);

#if WIN32
    OutputDebugStringA(message_buffer);
    fprintf(stdout, "%s", message_buffer);
#else
    write(1, message_buffer, length);
#endif
    if (level >= LEVEL_FATAL)
        HANGUP();
}
